package BenchmarkingClient;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.PropertyConfigurator;

import BenchmarkingClient.GuiInputParameters.ImplementationType;
import BenchmarkingClient.GuiInputParameters.MeasurementType;

/**
 * Klasse BenchmarkingGuiSimulation
 * 
 * Diese Klasse simuliert eine Benutzeroberflaeche fuer den
 * Start und die Steuerung eines Benchmark-Laufs.
 * 
 * Die Klasse kann durch eine eigene Klasse (evtl. Swing-GUI) ersetzt werden.
 * 
 * @author Mandl
 *
 */
public class BenchmarkingGuiSimulation implements BenchmarkingClientGuiInterface {
	
	private int timeCounter = 0;
	
	@Override
	public void showStartData(GuiStartData data) {
		
		System.out.println("Testbeginn: " + data.getStartTime());	
		System.out.println("Geplante Requests: " + data.getNumberOfRequests());
	}
	
	@Override
	public void showResultData(GuiResultData data) {
			
		System.out.println("Testende: " + data.getEndTime());
		System.out.println("Testdauer in s: " + data.getElapsedTime());	
		
		System.out.println("Gesendete Requests: " + data.getNumberOfSentRequests());
		System.out.println("Anzahl Responses: " + data.getNumberOfResponses());
		System.out.println("Anzahl verlorener Responses: " + data.getNumberOfLostResponses());
		
		System.out.println("Mittlere RTT in ms: " + data.getAvgRTT());
		System.out.println("Maximale RTT in ms: " + data.getMaxRTT());
		System.out.println("Minimale RTT in ms: " + data.getMinRTT());
		System.out.println("Mittlere Serverbearbeitungszeit in ms: " + data.getAvgServerTime());
		
		System.out.println("Maximale Heap-Belegung in MByte: " + data.getMaxHeapSize());
		System.out.println("Maximale CPU-Auslastung in %: " + data.getMaxCpuUsage());
	}
	
	@Override
	public void setMessageLine(String message) {
		System.out.println("*** Meldung: " + message+ " ***");
	}
	
	@Override
	public void addCurrentRunTime (long sec) {
		timeCounter += sec;
		System.out.println("Laufzeitzaehler: " + timeCounter);
	}
	
	@Override
	public void resetCurrentRunTime () {
		timeCounter = 0;
	}
	
	/**
	 * main
	 * @param args
	 */
	public static void main(String args[]) 
	{
		PropertyConfigurator.configureAndWatch("log4j.client.properties", 60 * 1000);
		
		/*

			int numberOfMessages;	   	// Anzahl der Nachrichten pro Client-Thread
										// Typ der Implementierung 
			ImplementationType implementationType; 								
										// Typ der Messung fuer das Messprotokoll 
			MeasurementType measurementType;
			int remoteServerPort;	   	// UDP- oder TCP-Port des Servers, Default: 50000 
			String remoteServerAddress;	// Server-IP-Adresse, Default: "127.0.0.1"

		*/
		
		String implementationTypes = "";
		
		for(ImplementationType i : ImplementationType.values()) {
			implementationTypes += i.name();
			implementationTypes += ", ";
		}
		
		Option type = OptionBuilder.isRequired().hasArg().withDescription("Type of benchmark (" + implementationTypes + ")").create("type");
		Option hostname = OptionBuilder.isRequired().hasArg().withDescription("Hostname of the echo-server").create("host");
		Option port = OptionBuilder.isRequired().hasArg().withDescription("Port of the echo-server.").create("port");
		Option numberOfClients = OptionBuilder.hasArg().withDescription("Amount of threads that will connect parallely to the echo server. Default 20").create("clients");
		Option numberOfMessages = OptionBuilder.hasArg().withDescription("Amount of messages that each thread will send. Default 100").create("messages");
		Option length = OptionBuilder.hasArg().withDescription("Message length. Default 50").create("length");
		Option thinktime = OptionBuilder.hasArg().withDescription("Waiting time in ms between two messages. Default 100").create("thinktime");
		Option measurementType = OptionBuilder.hasArg().withDescription("Type of measurement -> VarMsgLength or VarThreads. Default VarMsgLength").create("measurementType");
		
		Options options = new Options();
		options.addOption(type);
		options.addOption(hostname);
		options.addOption(port);
		options.addOption(numberOfClients);
		options.addOption(numberOfMessages);
		options.addOption(length);
		options.addOption(thinktime);
		options.addOption(measurementType);
		
		HelpFormatter formatter = new HelpFormatter();
		
		
		CommandLineParser parser = new GnuParser();
		
		try {
			CommandLine cl = parser.parse(options, args);

			GuiInputParameters parameters = new GuiInputParameters(cl.getOptionValue("type"), cl.getOptionValue("host"), Integer.parseInt(cl.getOptionValue("port")));
			
			if(cl.getOptionValue("clients") != null)
				parameters.setNumberOfClients(Integer.parseInt(cl.getOptionValue("clients")));
			
			if(cl.getOptionValue("messages") != null)
				parameters.setNumberOfMessages(Integer.parseInt(cl.getOptionValue("messages")));
			
			if(cl.getOptionValue("length") != null)
				parameters.setMessageLength(Integer.parseInt(cl.getOptionValue("length")));
			
			if(cl.getOptionValue("thinktime") != null)
				parameters.setClientThinkTime(Integer.parseInt(cl.getOptionValue("thinktime")));
			
			if(cl.getOptionValue("measurementType") != null)
				parameters.setMeasurementType(MeasurementType.valueOf(cl.getOptionValue("measurementType")));
			
			new BenchmarkingGuiSimulation().doWork(parameters);
			
		} catch (ParseException e) {
			formatter.printHelp( "BenchmarkingGuiSimulation", options );
			System.err.println(e.getMessage());
		}
	}
	
	public void doWork(GuiInputParameters parameters)
	{
		// Benchmarking-Client instanzieren und Benchmark starten
		
		BenchmarkingClient benchClient = new BenchmarkingClient();
		benchClient.executeTest(parameters, this);
	}
}